package com.videoanswer.van.common.dao.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public abstract class HibernateDao<ENTITY> extends HibernateDaoSupport implements IBaseDao<ENTITY>{

    ////////////////////////////////////////////////////////////////////////////
    //
    // Attributes
    
    /** The persistent class */
    private Class<ENTITY> m_class;	
	
    
	
	@Autowired
	public void setHibernateSessionFactory(@Qualifier("sessionFactory") SessionFactory sessinFactory){
		setSessionFactory(sessinFactory);
	}
	
    ////////////////////////////////////////////////////////////////////////////
    //
    // Methods	
	
    public HibernateDao (Class<ENTITY> cls){
        m_class = cls;
    }
    
    public Class<ENTITY> getPersistentClass (){
        return (m_class);
    }	
	
    
    @SuppressWarnings("unchecked")
	protected ENTITY loadUnique(final String sAttributeName, final Object oAttributeValue){
        return (m_class.cast (getHibernateTemplate().execute (new HibernateCallback<ENTITY> () {
            public ENTITY doInHibernate (Session session)
                throws HibernateException, SQLException {
                String sQuery = "FROM " + m_class.getName () + " o WHERE " + sAttributeName + " = :attribute";
                Query query = session.createQuery (sQuery);
                query.setParameter ("attribute", oAttributeValue);
                return ( (ENTITY)query.uniqueResult () );
            }
        })));
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // interface		
	public ENTITY save(final ENTITY entity) {
		
		return getHibernateTemplate().execute(new HibernateCallback<ENTITY>() {

//			@Override
			public ENTITY doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				session.save(entity);
				session.refresh(entity);
				return entity;
			}
		});
		
	}

	public void delete(final ENTITY entity) {
       getHibernateTemplate().execute(new HibernateCallback<ENTITY>() {

//			@Override
			public ENTITY doInHibernate(Session session)
					throws HibernateException, SQLException {

				session.delete(entity);

                return entity;
			}
		});

	}

    public void delete(List<ENTITY> entities) {

        getHibernateTemplate().deleteAll(entities);
    }

    public void saveOrUpdateAll(List<ENTITY> entities) {

        getHibernateTemplate().saveOrUpdateAll(entities);
    }

	public ENTITY update(final ENTITY entity) {

		return getHibernateTemplate().execute(new HibernateCallback<ENTITY>() {

//			@Override
			public ENTITY doInHibernate(Session session)
					throws HibernateException, SQLException {

				session.update(entity);
                session.flush();
                session.refresh(entity);
				return entity;
			}
		});
	}

    public void updateAll(final List<ENTITY> entities) {

        getHibernateTemplate().execute(new HibernateCallback<ENTITY>() {

//            @Override
            public ENTITY doInHibernate(Session session)
                    throws HibernateException, SQLException {

                for (ENTITY one : entities){
                    session.update(one);
                    session.flush();
                    session.refresh(one);
                }

                return null;
            }
        });
    }

	public ENTITY load(Serializable id) {
		return getHibernateTemplate().load(m_class, id);
	}

	/**
     * @param sql - Query
     * @return - List of results
     */
	@SuppressWarnings("unchecked")
    protected List<ENTITY> executeHQL(final String hql, final String[] paramNames, final Object[] params) {
        return getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
            	Query q = session.createQuery(hql);
                if(params != null && params.length > 0) {
               	 for(int i = 0; i < params.length; i ++) {
               		 if(params[i] instanceof Collection) {
               			 Collection ps = (Collection) params[i];
               			 if(ps.size() > 0) {
                   			 q.setParameterList(paramNames[i], ps);
               			 }
               		 } else {
               			 q.setParameter(paramNames[i], params[i]);
               		 }
                    }
               }
                return q.list();
            }
        });
    }

    @SuppressWarnings("unchecked")
    protected List<ENTITY> executePagingHQL(final String hql, final String[] paramNames, final Object[] params,final int pageNo,final int pageSize) {
        return getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q = session.createQuery(hql);
                if(params != null && params.length > 0) {
                    for(int i = 0; i < params.length; i ++) {
                        if(params[i] instanceof Collection) {
                            Collection ps = (Collection) params[i];
                            if(ps.size() > 0) {
                                q.setParameterList(paramNames[i], ps);
                            }
                        } else {
                            q.setParameter(paramNames[i], params[i]);
                        }
                    }
                }
                q.setFirstResult((pageNo-1)*pageSize);
                q.setMaxResults(pageSize);

                return q.list();
            }
        });
    }

    @SuppressWarnings("unchecked")
    protected int executeCountHQL(final String hql, final String[] paramNames, final Object[] params) {
        List<Long> rs = getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q = session.createQuery(hql);
                if(params != null && params.length > 0) {
                    for(int i = 0; i < params.length; i ++) {
                        if(params[i] instanceof Collection) {
                            Collection ps = (Collection) params[i];
                            if(ps.size() > 0) {
                                q.setParameterList(paramNames[i], ps);
                            }
                        } else {
                            q.setParameter(paramNames[i], params[i]);
                        }
                    }
                }
                return q.list();
            }
        });

        return rs != null ? !rs.isEmpty() ? rs.get(0).intValue() : 0 : 0;
    }
	
	@SuppressWarnings("unchecked")
    protected void executeUpdateSQL(final String sql, final String[] paramNames, final Object[] params) {
        if(paramNames == null || params == null || paramNames.length != params.length) {
        	return;
        }
    	getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery q = session.createSQLQuery(sql);
                if(params != null && params.length > 0) {
                	 for(int i = 0; i < params.length; i ++) {
                		 if(params[i] instanceof Collection) {
                			 Collection ps = (Collection) params[i];
                			 if(ps.size() > 0) {
                    			 q.setParameterList(paramNames[i], ps);
                			 }
                		 } else {
                			 q.setParameter(paramNames[i], params[i]);
                		 }
                     }
                }
                return q.executeUpdate();
            }
        });
    }

    @SuppressWarnings("unchecked")
    protected void executeSQL_noParam(final String sql) {

        getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery q = session.createSQLQuery(sql);

                return q.executeUpdate();
            }
        });
    }

    @SuppressWarnings("unchecked")
    protected int executeUpdateHQL(final String hql, final String[] paramNames, final Object[] params) {
        List<Long> rs = getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q = session.createQuery(hql);
                if(params != null && params.length > 0) {
                    for(int i = 0; i < params.length; i ++) {
                        if(params[i] instanceof Collection) {
                            Collection ps = (Collection) params[i];
                            if(ps.size() > 0) {
                                q.setParameterList(paramNames[i], ps);
                            }
                        } else {
                            q.setParameter(paramNames[i], params[i]);
                        }
                    }
                }
                return q.executeUpdate();
            }
        });

        return rs != null ? !rs.isEmpty() ? rs.get(0).intValue() : 0 : 0;
    }
}
